/******************************************************************************
**
**  COPYRIGHT (C) 2002 Intel Corporation.
**
**  This software as well as the software described in it is furnished under
**  license and may only be used or copied in accordance with the terms of the
**  license. The information in this file is furnished for informational use
**  only, is subject to change without notice, and should not be construed as
**  a commitment by Intel Corporation. Intel Corporation assumes no
**  responsibility or liability for any errors or inaccuracies that may appear
**  in this document or any software that may be provided in association with
**  this document.
**  Except as permitted by such license, no part of this document may be
**  reproduced, stored in a retrieval system, or transmitted in any form or by
**  any means without the express written consent of Intel Corporation.
**
**  FILENAME:       KeypadTest.c
**
**  PURPOSE:        This file contains the Bulverde Keypad POST code for
**                  the Intel(r) XScale(tm) Microarchitecture.
**
**  LAST MODIFIED:  $Modtime: 9/20/02 9:52a $
******************************************************************************/

/*
*******************************************************************************
*   HEADER FILES
*******************************************************************************
*/

#include "KeypadTest.h"
#include "gpio.h"
#include "udelay.h"
#include "util.h"
/*
*******************************************************************************
*   GLOBAL DEFINITIONS
*******************************************************************************
*/


/*
*******************************************************************************
*   LOCAL DEFINITIONS
*******************************************************************************
*/


/*
*******************************************************************************
*    Bulverde MSHC Registers
*******************************************************************************
*/
typedef unsigned long   UINT32;

#define KPC_REG         (*(volatile UINT32 *) 0x41500000)
#define KPDK_REG        (*(volatile UINT32 *) 0x41500008)
#define KPREC_REG       (*(volatile UINT32 *) 0x41500010)
#define KPMK_REG        (*(volatile UINT32 *) 0x41500018)
#define KPAS_REG        (*(volatile UINT32 *) 0x41500020)
#define KPASMKP0_REG    (*(volatile UINT32 *) 0x41500028)
#define KPASMKP1_REG    (*(volatile UINT32 *) 0x41500030)
#define KPASMKP2_REG    (*(volatile UINT32 *) 0x41500038)
#define KPASMKP3_REG    (*(volatile UINT32 *) 0x41500040)
#define KPKDI_REG       (*(volatile UINT32 *) 0x41500048)

/*
*******************************************************************************
*    Bulverde Keypad Register Field Macros
*******************************************************************************
*/
#define KEYP_KPC_ASACT            (0x1 <<  29)  // Automatic Scan on Activity
#define KEYP_KPC_MKRN             (0x3 <<  26)  // Number of Keypad Rows
#define KEYP_KPC_MKCN             (0x4 <<  23)  // Number of Keypad Columns
#define KEYP_KPC_MI               (0x1 <<  22)  // Matrix interrupt bit
#define KEYP_KPC_IMKP             (0x1 <<  21)  // Ignore Multiple Key Press
#define KEYP_KPC_MS7              (0x1 <<  20)  // Matrix scan line 3
#define KEYP_KPC_MS6              (0x1 <<  19)  // Matrix scan line 3
#define KEYP_KPC_MS5              (0x1 <<  18)  // Matrix scan line 3
#define KEYP_KPC_MS4              (0x1 <<  17)  // Matrix scan line 3
#define KEYP_KPC_MS3              (0x1 <<  16)  // Matrix scan line 3
#define KEYP_KPC_MS2              (0x1 <<  15)  // Matrix scan line 2
#define KEYP_KPC_MS1              (0x1 <<  14)  // Matrix scan line 1
#define KEYP_KPC_MS0              (0x1 <<  13)  // Matrix scan line 0
#define KEYP_KPC_ME               (0x1 <<  12)  // Matrix Keypad Enable
#define KEYP_KPC_DKIN             (0x2 <<   6)  // Direct Key Number -1
#define KEYP_KPC_DI               (0x1 <<   5)  // Direct key interrupt bit
#define KEYP_KPC_REE0             (0x1 <<   2)  // Rotary Encoder 0 Enable
#define KEYP_KPC_DE               (0x1 <<   1)  // Direct Keypad Enable

/*
*******************************************************************************
*    Keypad Register Macros
*******************************************************************************
*/



/*
*******************************************************************************
*    Bulverde GPIO Registers used by the Keypad
*******************************************************************************
*/
#define GPDR2_REG       (*(volatile UINT32 *) 0x40e00014)
#define GPDR3_REG       (*(volatile UINT32 *) 0x40e0010c)
#define GAFR2_U_REG     (*(volatile UINT32 *) 0x40e00068)
#define GAFR3_L_REG     (*(volatile UINT32 *) 0x40e0006c)
#define LED_MASK        (*(volatile UINT32 *) 0x08000040)
#define HEX_LEDS        (*(volatile UINT32 *) 0x08000010)

/*
*******************************************************************************
*    Mainstone Platform Registers for the Keypad
*******************************************************************************
*/

/*
*******************************************************************************
*  Error sub-location codes for ERR_L_KEYPAD location code
*******************************************************************************
*/
#define ERR_S_KEYPAD_INIT               0x01 // HW Initialization
#define ERR_S_KEYPAD_PASS               0x08 // Test Result = PASS
#define ERR_S_KEYPAD_FAIL               0x09 // Test Result = FAIL

/*
*******************************************************************************
*  Return Codes
*******************************************************************************
*/
#define KP_TEST_SUCCESS    0
#define KP_TEST_FAILURE    1

/********************************/
#define MAXBUTTON   28

#define DOWN    0
#define UP  1

/********************************/



void wls_keypad_init()
{
    volatile int *regT;

    //init keypad clock enable
    regT = (volatile int *)(0x41300004);
    *regT |= (1 << 19);

    //init gpio alternate function
    //set MKOUT0
    xs_setgpio_dir(103, GPIO_PIN_OUT);
    xs_setgpio_AFR(103, GPIO_AS_AF2);
    //set MKOUT1
    xs_setgpio_dir(104, GPIO_PIN_OUT);
    xs_setgpio_AFR(104, GPIO_AS_AF2);
    //set MKOUT2
    xs_setgpio_dir(105, GPIO_PIN_OUT);
    xs_setgpio_AFR(105, GPIO_AS_AF2);
    //set MKOUT5
    xs_setgpio_dir(108, GPIO_PIN_OUT);
    xs_setgpio_AFR(108, GPIO_AS_AF2);
    //set MKOUT6
    xs_setgpio_dir(96, GPIO_PIN_OUT);
    xs_setgpio_AFR(96, GPIO_AS_AF3);
    //set MKIN0
    xs_setgpio_dir(100, GPIO_PIN_IN);
    xs_setgpio_AFR(100, GPIO_AS_AF1);
    //set MKIN1
    xs_setgpio_dir(101, GPIO_PIN_IN);
    xs_setgpio_AFR(101, GPIO_AS_AF1);
    //set MKIN2
    xs_setgpio_dir(102, GPIO_PIN_IN);
    xs_setgpio_AFR(102, GPIO_AS_AF1);
    //set MKIN3
    xs_setgpio_dir(97, GPIO_PIN_IN);
    xs_setgpio_AFR(97, GPIO_AS_AF3);
    //set MKIN4
    xs_setgpio_dir(98, GPIO_PIN_IN);
    xs_setgpio_AFR(98, GPIO_AS_AF3);
    //set MKIN5
    xs_setgpio_dir(99, GPIO_PIN_IN);
    xs_setgpio_AFR(99, GPIO_AS_AF3);

    /* wls_setgpio_dir(120, GPIO_PIN_OUT); */
    /* wls_setgpio_AFR(120, GPIO_AS_GPIO); */
    /* wls_setgpio_outlow(120); */
    //init keypad control register
    //KPC_REG = (KEYP_KPC_ASACT | KEYP_KPC_MKRN | KEYP_KPC_MKCN |
    KPC_REG = (KEYP_KPC_ASACT | (5<<26)| (6<<23)|
               KEYP_KPC_ME | KEYP_KPC_DKIN | KEYP_KPC_REE0 | KEYP_KPC_DE |
               KEYP_KPC_MS0 | KEYP_KPC_MS1 | KEYP_KPC_MS2 | KEYP_KPC_MS5 | KEYP_KPC_MS6);

    KPKDI_REG = 1;    // Set Debounce time low because the rotary encoder also used this value!
    KPREC_REG = 0x7F;

    udelay(1);
}

char wls_keypad_getkey()
{
    char KeyData;             // Character from Keypad
    unsigned int KPData0;     // Register data
    unsigned int KPData1;     // Register data
    unsigned int KPPress;     // Keypad press count
    int timer;                // Loop coutner/timer (for test timeout)

    KeyData = 0x30;                           // Inital setting = ASCII ?
    timer = 20;                              // This will provide about a 10 second timeout

    while (((KPC_REG & KEYP_KPC_MI) != KEYP_KPC_MI) & (timer != 0) & ( ( KPAS_REG & 0x7C000000 ) == 0 ) )
    {
        timer = timer -1;         // Decrement timer
        udelay(1);            // Dealy 50 mS as part of timeout loop
    }

    if (timer == 0)
    {
        KeyData = 0x54;     // ASCII "T" for Time out
        return (KeyData);
    }

    // Code picks up here if a key is pressed

    udelay(10);   // Dealy 50 mS for data to settle

    KPData0 = KPAS_REG;                        //COLUMN
    KPData1 = (KPData0 & 0xF0) >> 4;           // Extract Row data and right justify
    KPPress = (KPData0 & 0x7C000000) >> 26;    // Extract key press count and right justify
    KPData0 = KPData0 & 0xF;                   // Isolate Column Data

    //printk("KP %x, %x, %x\n", KPPress, KPData1, KPData0);

    KeyData = 0x80;
#if !defined(_RELEASE) || defined(_PRERELEASE)
    if (KPPress == 1)                         // Decode only if 1 keypress has been detected
    {
        switch (KPData0)
        {
            case 0:
            if(KPData1 == 3) KeyData = 0x03;  // Key 2
            if(KPData1 == 4) KeyData = 0x02;  // Key 1
            if(KPData1 == 5) KeyData = 0x12;  // Key up
            break;

            case 1:
            if(KPData1 == 2) KeyData = 0x08;  // Key 6
            if(KPData1 == 3) KeyData = 0x06;  // Key 5
            if(KPData1 == 4) KeyData = 0x05;  // Key 4
            if(KPData1 == 5) KeyData = 0x24;  // Key down
            break;

        case 2:
            if(KPData1 == 1) KeyData = 0x04;  // Key   3
            if(KPData1 == 2) KeyData = 0x0b;  // Key   9
            if(KPData1 == 3) KeyData = 0x0a;  // Key   8
            if(KPData1 == 4) KeyData = 0x09;  // Key   7
            if(KPData1 == 5) KeyData = 0x21;  // Key   left
            break;

        case 5:
            if(KPData1 == 2) KeyData = 0x20;  // Key NumberSign
            if(KPData1 == 3) KeyData = 0x2e;  // Key 0
            if(KPData1 == 4) KeyData = 0x1e;  // Key Asterisk
            if(KPData1 == 5) KeyData = 0x17;  // Key right
            break;

        case 6:
            if(KPData1 == 2) KeyData = 0x26;   // Key F2
            if(KPData1 == 3) KeyData = 0x19;  // Key F1
            if(KPData1 == 4) KeyData = 0x32;  // Key F5
            if(KPData1 == 5) KeyData = 0x22;   // Key OK
            break;

        }
    }
#endif

    if (KPPress == 2) {
        printk("KPASMK %08x, %08x, %08x, %08x\n",
            KPASMKP0_REG, KPASMKP1_REG, KPASMKP2_REG, KPASMKP3_REG);

        unsigned long c5 = (KPASMKP2_REG & ~(1UL << 31)) >> 16 & 0xff;

        if ((c5 & 1 << 2) && (c5 & 1 << 4)) {//MultiKey * #
            KeyData = 0x2e;  // Key 0
        }
    }

    /* printk( "wls_keypad_getkey:0x%x\r\n", KeyData ); */
    return (KeyData);
}

void keyTest()
{
    int key, i = 100;
    wls_keypad_init();

    while( i-- ){
        key = wls_keypad_getkey();
        printk("keytest---key = 0x%x\n", key);
        udelay( 1 );
    }
}


int Do_Test_Keypad(char *param)
{
    int key = wls_keypad_getkey();
    printk("Got Key %x\n", key);
    return 0;
}


/* #include "logo.h" */

/* void Disable_Vibrator(void) */
/* { */
/*  set_GPIO_mode (89 | GPIO_OUT); */
/*  setgpio_outlow (89); */
/* }  */

/* void Enable_Vibrator(unsigned int flag) */
/* { */
/*  set_GPIO_mode(89 | GPIO_OUT); */
/*  setgpio_outhigh(89); */
/* } */

